#include "SingleInstruction.h"
#include "Function.h"

/// @brief 构造函数
/// @param _func 所属函数
/// @param _op 操作符
/// @param _srcVal 源操作数
/// @param _type 结果类型
SingleInstruction::SingleInstruction(Function * _func, IRInstOperator _op, Value * _srcVal, Type * _type)
    : Instruction(_func, _op, _type)
{
    addOperand(_srcVal);
}

/// @brief 转换成字符串
/// @param str 转换后的字符串
void SingleInstruction::toString(std::string & str)
{
    Value *src = getOperand(0);

    // 检测是否为内存变量
    std::string srcName;
    if (dynamic_cast<LocalVariable*>(src) != nullptr)  {
        // 如果是内存变量，生成临时变量并插入 load 指令
        RegVariable *tempVar = func->newTempVariable(src->getType());
        srcName = tempVar->getIRName();
        str += srcName + " = load " + src->getType()->toString() + ", " + src->getType()->toString() + "* " + src->getIRName() + "\n\t";
    } else {
        // 如果不是内存变量，直接使用变量名
        srcName = src->getIRName();
    }

    // 根据操作符和类型生成单操作数指令
    switch (op) {
        case IRInstOperator::IRINST_OP_LNOT_I:
            if (src->getType()->isIntegerType()) {
                str += getIRName() + " = icmp eq " + src->getType()->toString() + " " + srcName + ", 0";
            } else if (src->getType()->isFloatType()) {
                str += getIRName() + " = fcmp oeq " + src->getType()->toString() + " " + srcName + ", 0.0";
            }
            break;
        case IRInstOperator::IRINST_OP_UNARY_MINUS_I:
            if (src->getType()->isIntegerType()) {
                str += getIRName() + " = sub nsw " + src->getType()->toString() + " 0, " + srcName;
            } else if (src->getType()->isFloatType()) {
                str += getIRName() + " = fsub " + src->getType()->toString() + " 0.0, " + srcName;
            }
            break;
        case IRInstOperator::IRINST_OP_UNARY_PLUS_I:
            if (src->getType()->isIntegerType()) {
                str += getIRName() + " = add nsw " + src->getType()->toString() + " 0, " + srcName;
            } else if (src->getType()->isFloatType()) {
                str += getIRName() + " = fadd " + src->getType()->toString() + " 0.0, " + srcName;
            }
            break;
        default:
            Instruction::toString(str);
            break;
    }
}